/*
 * TraceVariBlock.c
 *
 *  Created on: 2012/07/10
 *      Author: guanxiaoying
 */
#include <float.h>
#include "../tracedef.h"
#include "trace_cmd.h"


AST Tr_VarBlkGetVariOrAdd( AST astVari, AST astCurrBlk ){
	AST astFirst;

	astFirst = Tr_VarBlkGetVari( astVari, astCurrBlk );
	if( astFirst == 0 ){
		astFirst = Tr_VarBlkAddVari( astVari, astCurrBlk );
	}
	return astFirst;
}
AST Tr_VarBlkGetVari( AST astVari, AST astCurrBlk ){
	AST astFirst;

	astFirst = stTrVariableBlockAccess.first.get( astCurrBlk );
	while( astFirst ){
		if( Tr_VariGetVari( astFirst ) == astVari ){
			return astFirst;
		}
		astFirst = Tr_VariGetNext( astFirst );
	}
	return 0;
}
AST Tr_VarBlkAddVari( AST astVari, AST astCurrBlk ){
	AST astEnd = stTrVariableBlockAccess.last.get( astCurrBlk );
	U4  size = stTrVariableBlockAccess.size.get( astCurrBlk );
	AST astTrVari;

	size++;
	stTrVariableBlockAccess.size.set( astCurrBlk, size );
	astTrVari = Tr_VariNew( astVari );
	if( size == 1 ){
		stTrVariableBlockAccess.first.set( astCurrBlk, astTrVari );
		stTrVariableBlockAccess.last.set( astCurrBlk, astTrVari );
	}else{
		Tr_VariSetNext( astEnd, astTrVari );
		Tr_VariSetPrev( astTrVari, astEnd );
	}
	return astTrVari;
}
VOID Tr_VarBlkDeleteVari( AST astVari, AST astCurrBlk ){
	AST astFirst;
	AST astEnd;
	U4  size = stTrVariableBlockAccess.size.get( astCurrBlk );
	AST astTrVari;
	if( size > 0 ){
		astTrVari = Tr_VarBlkGetVari( astVari, Tr_PathParamGetCurrVariBlock() );
		if( astTrVari > 0 ){
			size--;
			stTrVariableBlockAccess.size.set( astCurrBlk, size );
			if( size == 0 ){
				stTrVariableBlockAccess.first.set( astCurrBlk, 0 );
				stTrVariableBlockAccess.last.set( astCurrBlk, 0 );
			}else{
				astFirst = stTrVariableBlockAccess.first.get( astCurrBlk );
				astEnd = stTrVariableBlockAccess.last.get( astCurrBlk );
				if( astTrVari == astFirst ){
					astFirst = Tr_VariGetNext( astFirst );
					Tr_VariSetPrev( astFirst, 0  );
					stTrVariableBlockAccess.first.set( astCurrBlk, astFirst );
				}else if( astTrVari == astEnd ){
					astEnd = Tr_VariGetPrev( astEnd );
					Tr_VariSetNext( astEnd, 0  );
					stTrVariableBlockAccess.last.set( astCurrBlk, astEnd );
				}else{
					astFirst = Tr_VariGetPrev( astTrVari );
					astEnd = Tr_VariGetNext( astTrVari );
					Tr_VariSetNext( astFirst, astEnd );
					Tr_VariSetPrev( astEnd, astFirst );
				}
			}
		}
	}
}
VOID Tr_VarBlkClearAll( AST astBlk ){
	AST astFirst = stTrVariableBlockAccess.first.get( astBlk );
	stTrVariableBlockAccess.flag.set( astBlk, VARBLK_CLEARD );
	while( astFirst ){
		Tr_VariClearScope( astFirst );
		astFirst = Tr_VariGetNext( astFirst );
	}
}
BOOL Tr_VarBlkHasNoValueVariable( AST astBlk ){
	AST astFirstOrg;

	if( astBlk == 0 ){
		return FALSE;
	}
	astFirstOrg = stTrVariableBlockAccess.first.get( astBlk );
	while( astFirstOrg ){
		if( !Tr_VariHasValue( astFirstOrg ) ){
			return TRUE;
		}
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
	return FALSE;
}
BOOL Tr_VarBlkIsCleared( AST astBlk ){
	if( VARBLK_CLEARD & stTrVariableBlockAccess.flag.get( astBlk ) ){
		return TRUE;
	}
	return FALSE;
}
BOOL Tr_VarBlkIsBlank( AST astBlk ){
	if( Tr_VarBlkIsCleared( astBlk ) || ( 0 == stTrVariableBlockAccess.size.get( astBlk ) ) ){
		return TRUE;
	}
	return FALSE;
}
VOID Tr_VarBlkOrMergeTo( AST astOrgBlk, AST astDstBlk ){
	AST astFirstOrg;
	AST astFirstDst;
	BOOL clearFlg = Tr_VarBlkIsCleared( astDstBlk );
	if( Tr_VarBlkIsCleared( astOrgBlk ) ){
		return;
	}
	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		astFirstDst = stTrVariableBlockAccess.first.get( astDstBlk );
		while( astFirstDst ){
			if( Tr_VariGetVari( astFirstDst )
				== Tr_VariGetVari( astFirstOrg)){
				if( clearFlg ){
					Tr_VariReplaceValue( astFirstOrg, astFirstDst );
				}else{
					Tr_VariOrMergeValue( astFirstOrg, astFirstDst );
				}
			}
			astFirstDst = Tr_VariGetNext( astFirstDst );
		}
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
}
VOID Tr_VarBlkAndMergeTo( AST astOrgBlk, AST astDstBlk ){
	AST astFirstOrg;
	AST astFirstDst;
	BOOL clearFlg = Tr_VarBlkIsCleared( astDstBlk );
	if( Tr_VarBlkIsCleared( astOrgBlk ) ){
		Tr_VarBlkClearAll(astDstBlk);
		return;
	}
	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		astFirstDst = stTrVariableBlockAccess.first.get( astDstBlk );
		while( astFirstDst ){
			if( Tr_VariGetVari( astFirstDst )
				== Tr_VariGetVari( astFirstOrg)){
				if( !clearFlg ){
					Tr_VariAndMergeValue( astFirstOrg, astFirstDst );
				}
			}
			astFirstDst = Tr_VariGetNext( astFirstDst );
		}
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
}
VOID Tr_VarBlkReplace( AST astOrgBlk, AST astDstBlk ){
	AST astFirstOrg;
	AST astFirstDst;
	if( Tr_VarBlkIsCleared( astOrgBlk ) ){
		Tr_VarBlkClearAll(astDstBlk);
		return;
	}
	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		astFirstDst = stTrVariableBlockAccess.first.get( astDstBlk );
		while( astFirstDst ){
			if( Tr_VariGetVari( astFirstDst )
				== Tr_VariGetVari( astFirstOrg)){
				Tr_VariReplaceValue( astFirstOrg, astFirstDst );
			}
			astFirstDst = Tr_VariGetNext( astFirstDst );
		}
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
}
VOID Tr_VarBlkReverse( AST astOrgBlk ){
	AST astFirstOrg;

	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		Tr_VariReverseScope( astFirstOrg );
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
}
VOID Tr_VarBlkCopyNegationScp( AST astOrgBlk ){
	AST astFirstOrg;

	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		Tr_VariCopyNegationScp( astFirstOrg );
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
}

AST Tr_VarBlkCopyNew( AST astOrgBlk ){
	AST astFirstOrg;
	AST astFirstDst;
	AST astNewBlock;
	AST astVari;
	AST astPre = 0;
	U4 size;
	BOOL clearFlg = Tr_VarBlkIsCleared( astOrgBlk );

	stTrVariableBlockAccess.alloc(1);
	astNewBlock = stTrVariableBlockAccess.getMax();
	size = stTrVariableBlockAccess.size.get( astOrgBlk );
	stTrVariableBlockAccess.size.set( astNewBlock, size );

	size = stTrVariableBlockAccess.flag.get( astOrgBlk );
	stTrVariableBlockAccess.flag.set( astNewBlock, size );

	astFirstOrg = stTrVariableBlockAccess.first.get( astOrgBlk );
	while( astFirstOrg ){
		astVari = Tr_VariGetVari( astFirstOrg );
		astFirstDst = Tr_VariNew( astVari );
		Tr_VariReplaceValue( astFirstOrg, astFirstDst );
		if( astPre == 0 ){
			stTrVariableBlockAccess.first.set( astNewBlock, astFirstDst );
			stTrVariableBlockAccess.last.set( astNewBlock, astFirstDst );
		}else{
			Tr_VariSetNext( astPre, astFirstDst );
			Tr_VariSetPrev( astFirstDst, astPre );
			stTrVariableBlockAccess.last.set( astNewBlock, astFirstDst );
		}
		astPre = astFirstDst;
		astFirstOrg = Tr_VariGetNext( astFirstOrg );
	}
	if( clearFlg ){
		Tr_VarBlkClearAll(astNewBlock);
	}
	return astNewBlock;
}
AST Tr_VarBlkNewBlock( VOID ){
	stTrVariableBlockAccess.alloc(1);
	return stTrVariableBlockAccess.getMax();
}
VOID Tr_VarBlkClearAfter( AST ast ){
	stTrVariableBlockAccess.alloc( ast - stTrVariableBlockAccess.getMax() );
}
